package com.zhsource.system.service.impl;

import cn.hutool.core.util.ObjUtil;

import com.zhsource.auth.LoginDto;
import com.zhsource.auth.LoginJwtUtil;
import com.zhsource.auth.Payload;
import com.zhsource.auth.SecurityUserDetails;
import com.zhsource.exception.GlobalException;
import com.zhsource.system.domain.Logininfo;
import com.zhsource.system.domain.Menu;
import com.zhsource.system.mapper.MenuMapper;
import com.zhsource.system.service.ILoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private MenuMapper menuMapper;

    /**
     * 账号密码登录
     * @param loginDto
     * @return
     */
    @Override
    public String account(LoginDto loginDto) {
        // 1.生成一个不具备任何业务含义的令牌，这个令牌只是包含用户的账号密码信息
        String username = loginDto.getUsername() + "-" + loginDto.getType();
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, loginDto.getPassword());

        // 2.使用认证管理器对象，传入令牌得到认证对象，会自动去调用loadUserByUsername方法
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);

        // 3.认证对象如果为空那么就说明认证失败了
        if (ObjUtil.isEmpty(authenticate)){
            throw new GlobalException("用户账号或密码不正确！");
        }

        // 4.从认证对象中获取我们在认证时存的用户基本信息和权限信息
        Object principal = authenticate.getPrincipal();
        // 4.1.判断从认证对象中获取的对象是否是我们返回给security的对象，如果不是说明代码有异常
        if (!(principal instanceof SecurityUserDetails)){
            throw new GlobalException("系统异常，请重试！");
        }
        // 4.2.强转Object类型为我们自己的SecurityUserDetails对象
        SecurityUserDetails securityUserDetails = (SecurityUserDetails)principal;

        // 4.3.得到用户基本信息以及权限信息
        Logininfo logininfo = securityUserDetails.getLogininfo();
        List<String> permissionSns = securityUserDetails.getPermissionSns();

        // 5.判断当前用户是否是后台用户，如果是那么查询此用户的菜单信息
        List<Menu> menuTree = new ArrayList<>();
        if (0 == loginDto.getType()){
            //5,1 根据logininfoId查到此用户信息
          List<Menu>  menus = menuMapper.selectByLogininfoId(logininfo.getId());

            // 5.2 将list集合转换为map,用于解决双重for循环问题
            Map<Long, Menu> MenuMap = menus.stream().collect(Collectors.toMap(Menu::getId, value -> value));
            for (Menu menu : menus) {
                if (menu.getParentId()== null){
                    // 说明是一级
                    menuTree.add(menu);
                }else {
                    // 说明是子级
                    Menu parent = MenuMap.get(menu.getParentId());
                    if (!ObjUtil.isEmpty(parent)){
                        parent.getChildren().add(menu);
                    }
                }
            }
        }

        return LoginJwtUtil.generateTokenForUser(new Payload(logininfo, permissionSns, menuTree));
    }
}
